/**********************************************************************************
 ***
 ***    Screencasting Teaching System C++ Library
 ***    Copyright (C) 2011  Jiri Novak <jiri.novak@petriny.net>
 ***                        Wadi Jalil Maluf <wadijm@gmail.com>
 ***
 ***    This file is part of the Screencasting Teaching System C++ Library.
 ***
 ***    This library is free software; you can redistribute it and/or modify
 ***    it under the terms of the GNU General Public License as published by
 ***   the Free Software Foundation; either version 3 of the License, or
 ***    (at your option) any later version.
 ***
 ***    This library is distributed in the hope that it will be useful,
 ***    but WITHOUT ANY WARRANTY; without even the implied warranty of
 ***    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ***   GNU General Public License for more details.
 ***
 ***    You should have received a copy of the GNU General Public License
 ***    along with this library; if not, write to the Free Software
 ***    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ***
 *********************************************************************************/

#include <gtest/gtest.h>
#include <string>
#include <vector>
#include "../src/common/comm/socket.h"
#include "../src/common/comm/sockettcp.h"
#include "../src/common/comm/socketmsgsender.h"
#include "../src/common/comm/operation.h"
#include "../src/common/comm/blockingqueue.h"



/**
 * Test of blocking queue with socketsender
 */
TEST(SocketSenderTest, testSendingAndRecievingMessage) {

    // Init variables
    SocketTcp senderSocket;
    SocketTcp serverSocket;
    BlockingQueue* queue=new BlockingQueue;
    SocketMsgSender msgSender(queue,&senderSocket);

    // Init server socket
    bool abrio=serverSocket.open();
    EXPECT_TRUE(abrio);
    serverSocket.bindTo(9004);
    serverSocket.listenTo(10);

    // Init socket to send data
    abrio=senderSocket.open();
    EXPECT_TRUE(abrio);
    EXPECT_TRUE(senderSocket.connectTo("localhost",9004));

    // Start thread from socket sender
    msgSender.start();

    std::string msg="DATOS";
    std::vector<char> data(msg.size());
    msg.copy(&data[0], msg.size(), 0);
    queue->push(data);

    unsigned char buffer[30000];
    SocketTcp* s = serverSocket.acceptSocket();
    int cantidadLeidos=s->recibir(buffer,msg.size());
    EXPECT_EQ(cantidadLeidos, msg.size());
    buffer[msg.size()]=0;
    std::string recvData((char *)buffer);
    EXPECT_STREQ(msg.c_str(), (char *)buffer);

    // free resources
    s->closeSocket();
    delete s;
    serverSocket.closeSocket();
    msgSender.close();
    delete queue;
    msgSender.join();
}

/**
 * Test of blocking queue with socketsender
 */
TEST(SocketRecieverTest, testSendingAndRecievingMessageInOneBuffer) {

  // Init variables
  SocketTcp senderSocket;
  SocketTcp serverSocket;
  BlockingQueue* queue=new BlockingQueue;
  SocketMsgSender msgSender(queue,&senderSocket);

  // Init server socket
  bool abrio=serverSocket.open();

  serverSocket.bindTo(8009);
  serverSocket.listenTo(10);

  // Init socket to send data
  abrio=senderSocket.open();

  bool conecto=senderSocket.connectTo("localhost",8009);

  // Start thread from socket sender
  msgSender.start();

  std::string msg="DATOS";
  Operation op1;
  op1.setType(1);
  op1.setData(msg);
  std::vector<char> op1bytes=op1.serialize();

  std::string msg2="LLEGAN";
  Operation op2;
  op2.setType(1);
  op2.setData(msg2);
  std::vector<char> op2bytes=op2.serialize();

  std::string msg3="BIEN";
  Operation op3;
  op3.setType(1);
  op3.setData(msg3);
  std::vector<char> op3bytes=op3.serialize();

  int tamanioTotal=op1bytes.size()+op2bytes.size()+op3bytes.size();
  int tamanioEsperado=msg.size()+msg2.size()+msg3.size()+5*3;
  EXPECT_TRUE(tamanioTotal==tamanioEsperado);
  std::vector<char> todosJuntos(tamanioTotal);
  std::copy(op1bytes.begin(), op1bytes.end(), todosJuntos.begin());
  std::copy(op2bytes.begin(), op2bytes.end(), todosJuntos.begin()+op1bytes.size());
  std::copy(op3bytes.begin(), op3bytes.end(), todosJuntos.begin()+op1bytes.size()+op2bytes.size());

  std::cout<<tamanioTotal<< " "<<todosJuntos.size()<<std::endl;

  queue->push(todosJuntos);

  unsigned char buffer[30000];
  SocketTcp* s = serverSocket.acceptSocket();
  int cantidadLeidos=s->recibir(buffer,30000);
  std::cout<<tamanioTotal<< " "<<cantidadLeidos<<std::endl;

  Operation opTotal;

  opTotal.add(buffer,cantidadLeidos);
  EXPECT_TRUE(opTotal.isComplete());
 // EXPECT_STREQ(msg.c_str(), (char *)&opTotal.getDataBytes().at(0));
  opTotal.reset();
  EXPECT_TRUE(opTotal.isComplete());
//  EXPECT_STREQ(msg2.c_str(), (char *)&opTotal.getDataBytes().at(0));
  opTotal.reset();
  EXPECT_TRUE(opTotal.isComplete());
//  EXPECT_STREQ(msg3.c_str(), (char *)&opTotal.getDataBytes().at(0));
  opTotal.reset();
  EXPECT_TRUE(!opTotal.isComplete());
  EXPECT_TRUE(opTotal.getBuffer().size()==0);
  // free resources
  s->closeSocket();
  delete s;
  serverSocket.closeSocket();
  msgSender.close();
  delete queue;
  msgSender.join();

}

